/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package merlion.mrp.pmm.session;

import java.sql.Timestamp;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import merlion.common.util.Consts;
import merlion.mrp.pmm.entity.FinishedGood;
import merlion.mrp.ppm.entity.BOM;
import merlion.mrp.ppm.entity.DailyPlannedProduction;
import merlion.mrp.ppm.entity.Product;
import merlion.scm.icm.entity.ProductInventoryRecord;
import merlion.scm.icm.session.InventoryControlSessionBeanLocal;

/**
 *
 * @author Zhu Xin, Zhang Ying
 */
@Stateless
public class ProductManagementSession implements ProductManagementSessionLocal, ProductManagementSessionRemote {

    @PersistenceContext
    private EntityManager entityManager;
    @EJB
    private InventoryControlSessionBeanLocal icSessionBean;

    @Override
    public Product updateProductBasePrice(Product product) {
        if (product == null) {
            return null;
        }
        product.setBasePrice(roundToFourDecimals(product.getBasePrice()));
        product.setDsUnitPrice(product.getBasePrice() * product.getDsMarkup());
        product.setWsUnitPrice(product.getBasePrice() * product.getWsMarkup());
        entityManager.merge(product);
        return product;
    }

    private double roundToFourDecimals(double d) {
        DecimalFormat fourDForm = new DecimalFormat("#.####");
        return Double.valueOf(fourDForm.format(d));
    }

    @Override
    public Collection<FinishedGood> getAllFinishedGoods() {
        Query query = entityManager.createQuery("SELECT fd FROM FinishedGood fd");
        return query.getResultList();
    }

    @Override
    public FinishedGood createFinishedGoodsRecord(FinishedGood fg, Product p) {
        if (fg == null) {
            return null;
        }
        long oneDay = (long) (1 * 24 * 60 * 60 * 1000);
        long oneMonth = 30L * oneDay;
        Timestamp today = new Timestamp(System.currentTimeMillis());
        fg.setDateManufactured(new Timestamp(new Date().getTime()));
        fg.setDateShelf(new Timestamp(today.getTime() + oneMonth * (long) 10));
        fg.setDatePrinted(new Timestamp(today.getTime() + oneMonth * (long) 11));
        fg.setDateExpired(new Timestamp(today.getTime() + oneMonth * (long) 12));
        fg.setBasePrice(p.getBasePrice());
        fg.setInventory(icSessionBean.getProductInventoryRecordByProduct(p));
        //Reduce raw material inventory
        List<Double> consumed = calculateMaterialUsed(fg);
        boolean reduced = icSessionBean.consumeRawMaterialInventory(consumed);
        if(!reduced){
            System.out.println("Insufficient Raw Materials");
            return null;
        }
        fg = icSessionBean.addBatchToInventoryRecord(fg, p);
        fg = icSessionBean.arrangeBatchLocation(fg);
        

        return entityManager.merge(fg);
    }

    @Override
    public FinishedGood updateFinishedGoodsRecord(FinishedGood fg) {
        entityManager.merge(fg);
        return fg;
    }

    @Override
    public Boolean exist(String batchNo) {
        boolean exist = false;

        //Query finished goods table, any existing record
        Query query = entityManager.createQuery("SELECT fg FROM FinishedGood fg WHERE fg.batchNo LIKE :p1");
        query.setParameter("p1", batchNo);
        if (!query.getResultList().isEmpty()) {
            exist = true;
        }

        return exist;
    }

    @Override
    public FinishedGood getFinishedGoodsById(Long id) {

        Query query = entityManager.createQuery("SELECT fg FROM FinishedGood fg WHERE fg.id = :p1");
        query.setParameter("p1", id);
        if (query.getResultList().isEmpty()) {
            return null;
        } else {
            return (FinishedGood) query.getResultList().get(0);
        }

    }

    @Override
    public boolean checkPercDifferenceFromPlannedDaily(FinishedGood fg, String productType) {
        // return true if it is within 10%
        Long producedQty = fg.getQuantity();
        Query query = entityManager.createQuery("SELECT d FROM DailyPlannedProduction d WHERE d.product.productType=:p1");
        query.setParameter("p1", productType);
        List<DailyPlannedProduction> result = (List<DailyPlannedProduction>) query.getResultList();
        for (DailyPlannedProduction d : result) {
            SimpleDateFormat sdf = new SimpleDateFormat("ddMMyyyy");
            String formatedDate = sdf.format(fg.getDateManufactured());
            String dDate = sdf.format(d.getProductionDay());
            if (formatedDate.equals(dDate)) {
                return totalWithinTenPerc((d.getTotalDemand()), producedQty);
            }
        }
        // don't have the planned
        return false;
    }

    private boolean totalWithinTenPerc(Long totalPrev, Long inputtedTotal) {
        if (Math.abs(totalPrev - inputtedTotal) * 1.0 / totalPrev <= 0.1) {
            return true;
        } else {
            return false;
        }
    }
    
        @Override
    public List<Double> calculateMaterialUsed(FinishedGood fg) {

        ArrayList<BOM> boms = new ArrayList<BOM>(entityManager.createQuery("SELECT b FROM BOM b").getResultList());
        ArrayList<Double> used = new ArrayList<Double>();

        double quantityKg = 0d;
        int i = 0;
        if (fg.getInventory().getProduct().getProductType().equals(Consts.ProductType.BAR_A.getText())) {
            quantityKg = fg.getQuantity().doubleValue() * 240d * 0.05d;
            i = 0;
        }
        if (fg.getInventory().getProduct().getProductType().equals(Consts.ProductType.BAR_B.getText())) {
            quantityKg = fg.getQuantity().doubleValue() * 240d * 0.05d;
            i = 1;
        }
        if (fg.getInventory().getProduct().getProductType().equals(Consts.ProductType.BAR_C.getText())) {
            quantityKg = fg.getQuantity().doubleValue() * 200d * 0.0666d;
            i = 2;
        }
        if (fg.getInventory().getProduct().getProductType().equals(Consts.ProductType.BAR_D.getText())) {
            quantityKg = fg.getQuantity().doubleValue() * 200d * 0.0666d;
            i = 3;
        }

        for (BOM b : boms) {
            Double materialUsed;
            materialUsed = b.getMaterialRequirements().get(i).getValue() * quantityKg / (double)10;
            used.add(materialUsed);
            System.out.println((double)b.getMaterialRequirements().get(i).getValue() + " " + quantityKg + " " + (double)materialUsed + "");
        }

        return used;
    }
        
    @Override
     public Product getProduct(String productType){
         Query query = entityManager.createQuery("SELECT p FROM Product p WHERE p.productType = :p1");
         query.setParameter("p1", productType);
         Product p=(Product)query.getSingleResult();
         return p;
     
     }
     
//    ------------------------------------
//           for Junit Test
//    ------------------------------------
    @Override
     public Product createProduct(Product p){
         entityManager.merge(p);
         return p;
     }
    
    @Override
    public ProductInventoryRecord createProductInventoryRecord(ProductInventoryRecord pir){
        entityManager.merge(pir);
        return pir;
    }
}
